﻿using System;
using Kaleida.ServiceMonitor.Framework;
using NUnit.Framework;

namespace Kaleida.UnitTests.Framework
{
    [TestFixture]
    public class DurationParserTests
    {
        [Test]
        public void TestCanParseMilliseconds()
        {
            TestCanParse("123", "123 ms", TimeSpan.FromMilliseconds(123));
            TestCanParse("123.456", "123.456 ms", TimeSpan.FromMilliseconds(123.456));
            TestCanParse("1ms", "1 ms", TimeSpan.FromMilliseconds(1));
            TestCanParse("-1ms", "-1 ms", TimeSpan.FromMilliseconds(-1));
            TestCanParse("-2ms", "-2 ms", TimeSpan.FromMilliseconds(-2));
            TestCanParse("1.5ms", "1.5 ms", TimeSpan.FromMilliseconds(1.5));
            TestCanParse("-1.5ms", "-1.5 ms", TimeSpan.FromMilliseconds(-1.5));
            TestCanParse(" 4ms ", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse(" 4MS ", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse(" 4mS ", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse("4 millisecond", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse("4 MilliSecOnd", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse("4 milliseconds", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse("4 milli seconds", "4 ms", TimeSpan.FromMilliseconds(4));
            TestCanParse("4 milli-seconds", "4 ms", TimeSpan.FromMilliseconds(4));
        }

        [Test]
        public void TestCanParseSeconds()
        {
            TestCanParse("1s", "1 sec", TimeSpan.FromSeconds(1));
            TestCanParse("-1s", "-1 sec", TimeSpan.FromSeconds(-1));
            TestCanParse("-2s", "-2 secs", TimeSpan.FromSeconds(-2));
            TestCanParse("1.5s", "1.5 secs", TimeSpan.FromSeconds(1.5));
            TestCanParse("-1.5s", "-1.5 secs", TimeSpan.FromSeconds(-1.5));
            TestCanParse(" 4s ", "4 secs", TimeSpan.FromSeconds(4));
            TestCanParse(" 4S ", "4 secs", TimeSpan.FromSeconds(4));
            TestCanParse("4 second", "4 secs", TimeSpan.FromSeconds(4));
            TestCanParse("4 SeCond", "4 secs", TimeSpan.FromSeconds(4));
            TestCanParse("4 seconds", "4 secs", TimeSpan.FromSeconds(4));
        }

        [Test]
        public void TestCanParseMinutes()
        {
            TestCanParse("1m", "1 min", TimeSpan.FromMinutes(1));
            TestCanParse("-1m", "-1 min", TimeSpan.FromMinutes(-1));
            TestCanParse("-2m", "-2 mins", TimeSpan.FromMinutes(-2));
            TestCanParse("1.5m", "1.5 mins", TimeSpan.FromMinutes(1.5));
            TestCanParse("-1.5m", "-1.5 mins", TimeSpan.FromMinutes(-1.5));
            TestCanParse(" 4m ", "4 mins", TimeSpan.FromMinutes(4));
            TestCanParse(" 4M ", "4 mins", TimeSpan.FromMinutes(4));
            TestCanParse("4 minute", "4 mins", TimeSpan.FromMinutes(4));
            TestCanParse("4 MinUte", "4 mins", TimeSpan.FromMinutes(4));
            TestCanParse("4 minutes", "4 mins", TimeSpan.FromMinutes(4));
        }

        [Test]
        public void TestCanParseHours()
        {
            TestCanParse("1h", "1 hr", TimeSpan.FromHours(1));
            TestCanParse("-1h", "-1 hr", TimeSpan.FromHours(-1));
            TestCanParse("-2h", "-2 hrs", TimeSpan.FromHours(-2));
            TestCanParse("1.5h", "1.5 hrs", TimeSpan.FromHours(1.5));
            TestCanParse("-1.5h", "-1.5 hrs", TimeSpan.FromHours(-1.5));
            TestCanParse(" 4h ", "4 hrs", TimeSpan.FromHours(4));
            TestCanParse(" 4H ", "4 hrs", TimeSpan.FromHours(4));
            TestCanParse("4 hour", "4 hrs", TimeSpan.FromHours(4));
            TestCanParse("4 HoUr", "4 hrs", TimeSpan.FromHours(4));
            TestCanParse("4 hours", "4 hrs", TimeSpan.FromHours(4));
        }

        [Test]
        public void TestCanParseDays()
        {
            TestCanParse("1d", "1 day", TimeSpan.FromDays(1));
            TestCanParse("-1d", "-1 day", TimeSpan.FromDays(-1));
            TestCanParse("-2d", "-2 days", TimeSpan.FromDays(-2));
            TestCanParse("1.5d", "1.5 days", TimeSpan.FromDays(1.5));
            TestCanParse("-1.5d", "-1.5 days", TimeSpan.FromDays(-1.5));
            TestCanParse(" 4d ", "4 days", TimeSpan.FromDays(4));
            TestCanParse(" 4D ", "4 days", TimeSpan.FromDays(4));
            TestCanParse("4 day", "4 days", TimeSpan.FromDays(4));
            TestCanParse("4 DaY", "4 days", TimeSpan.FromDays(4));
            TestCanParse("4 days", "4 days", TimeSpan.FromDays(4));
        }

        [Test]
        public void TestCannotParseBadInput()
        {
            Assert.IsFalse(DurationParser.CanParse("ms1"));
            Assert.IsFalse(DurationParser.CanParse("-1-ms"));
            Assert.IsFalse(DurationParser.CanParse("abc"));
            Assert.IsFalse(DurationParser.CanParse("123abc"));
        }

        [Test, ExpectedException(typeof(FormatException), ExpectedMessage = "Cannot parse '123 abc' as a duration. The following suffices may be used: day, hr, min, sec, ms")]
        public void TestExceptionIsThrownIfTryParseDurationWithBadInput()
        {
            DurationParser.ParseDuration("123 abc");
        }

        [Test, ExpectedException(typeof(FormatException), ExpectedMessage = "Cannot parse '123 abc' as a duration. The following suffices may be used: day, hr, min, sec, ms")]
        public void TestExceptionIsThrownIfTryParseTimeSpanWithBadInput()
        {
            DurationParser.ParseTimeSpan("123 abc");
        }


        private static void TestCanParse(string input, string expectedCanonicalised, TimeSpan expectedTimeSpan)
        {
            Assert.IsTrue(DurationParser.CanParse(input), "Expected to be able to parse '{0}'", input);
            Assert.AreEqual(expectedCanonicalised, DurationParser.ParseDuration(input).ToString(), "expected canonical representation of '{0}' to be '{1}'", input, expectedCanonicalised);
            Assert.AreEqual(expectedTimeSpan, DurationParser.ParseTimeSpan(input), "expected TimeSpan of '{0}' to be '{1}'", input, expectedTimeSpan.ToFormattedString());
        }
    }
}
